#ifndef YEPXML_WRITTER_HPP
#define YEPXML_WRITTER_HPP

#include "document.hpp"
#include <ostream>

namespace yxml
{
    /**
     * @brief The base class for writting a xml document
     **/
    class Writter
    {
    public:
        /**
         * @brief Constructs a new writter
         *
         * @param out The output stream
         **/
        Writter(ostream & out):_out(out) {}

        /**
         * @brief writtes the given document on stream.
         * @param document The document to be written
         **/
        virtual void write(Document &document);
    protected:
        /**
         * @brief write the header tag.
         *
         * The header tag should look as follows:
         * @code
         *  <?xml version="1.0" standalone="yes" encoding="UTF-8" ?>
         * @endcode
         **/
        virtual void writeHeaderTag(Document &document);

        /**
         * @brief Writes a node.
         *
         * A node is a xml element, such a tag, a text or comment.
         **/
        virtual void writeNode(Node &node);

        /**
         * @brief Writes a tag node.
         **/
        virtual void writeTag(Node &node);

        /**
         * @brief Writes a text node.
         **/
        virtual void writeText(Node &node);

        /**
         * @brief Writes a comment node.
         **/
        virtual void writeComment(Node &node);

        /**
         * @brief Writes a tag attribute.
         **/
        virtual void writeAttribute(const string &key, const string &value);

        /**
         * @brief Writes the sub nodes from a tag
         **/
        virtual void writeSubNodes(Node &node);

        /**
         * @brief Fix string of a attribute
         *
         * Replaces the '<b>\\</b>' for '<b>\\\\</b>', '<b>\"</b>' for '<b>\\"</b>' and '<b>\'</b>' for '<b>\\'</b>'
         **/
        virtual string fixString(string s);

        /**
         * Prints the char on stream
         **/
        void putChar(char c)
        {
            _out << fixTextChar(c);
        }

        /**
         * Fix a text character.
         *
         * Replaces the '<b>&amp;</b>' for '<b>&amp;amp;</b>', '<b>&lt;</b>' for '<b>&amp;lt;</b>' and '<b>&gt;</b>' for '<b>&amp;gt;</b>'
         **/
        virtual string fixTextChar(char c)
        {
            switch ( c )
            {
            case '&':
                return "&amp;";
            case '<':
                return "&lt;";
            case '>':
                return "&gt;";
            default:
                return string() + c;
            }
        }

        /**
         * @brief Fix the text.
         *
         * Aplies the fixTextChar to every char on the text.
         **/
        virtual string fixText(string s);

        /**
         * @brief The output stream. It is defined on the constructor and can't be changed.
         **/
        ostream & _out;
    };
}

#endif // YEPXML_WRITTER_HPP
